package service

import (
	"gobase/util"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/casbin/casbin"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"github.com/xormplus/xorm"
)

type RoleUserService struct {
	dao *xorm.Engine
	log *logrus.Logger
	ce  *casbin.Enforcer
}

//初始化方法
func NewRoleUserService(c *gin.Context) *RoleUserService {
	return &RoleUserService{dao: util.GetDb(c), log: util.GetLog(c), ce: util.GetCasbin(c)}
}

//获取角色用户
func (srv *RoleUserService) GetRoleUserList(roleid int) []map[string]string {
	sql := "SELECT t.* FROM ( SELECT u.id, u.username AS name, CONCAT('org', u.orgid) AS pid, 0 AS isParent, (CASE WHEN ru.id THEN 1 ELSE 0 END) AS checked, 10000 AS sortnum, 1 AS isuser FROM USER AS u LEFT JOIN role_user AS ru ON ru.userid = u.id AND ru.roleid = ? UNION ALL SELECT CONCAT('org', o.id) AS id, o.`name`, CONCAT('org', o.parent_id) AS pid, 1 AS isParent, 0 AS checked, o.sortnum, 0 AS isuer FROM org AS o ) AS t ORDER BY t.pid, t.sortnum "

	sliceStrList, err := srv.dao.SQL(sql, roleid).QueryString()
	if err != nil {
		srv.log.Errorf("RoleUserService->GetRoleUserList 获取角色用户：%s", err)
	}
	return sliceStrList
}

//根据用户ID 获取角色用户关联
func (srv *RoleUserService) GetRolesByUid(userid int64) []map[string]string {
	sql := "SELECT t.id, t.rolename, (CASE WHEN ru.id THEN 1 ELSE 0 END) AS ischeck FROM role AS t LEFT JOIN role_user AS ru ON ru.roleid = t.id AND ru.userid = ? "
	roleList, err := srv.dao.SQL(sql, userid).QueryString()

	if err != nil {
		srv.log.Errorf("RoleUserService->GetRolesByUid：%s", err)
	}
	return roleList
}

//授权用户
//roleid int 角色ID
//userIds []string 所需用户
//写入 role_user表
func (srv *RoleUserService) AuthorizeUser(roleid int, userIds []string) error {
	session := srv.dao.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		return errors.Wrap(err, "开启事务失败!")
	}

	//删除已有的关联
	_, err := session.Sql("delete from role_user where roleid=?", roleid).Execute()
	if err != nil {
		return errors.Wrap(err, "删除角色已关联用户失败!")
	}

	//保存新的关联
	if len(userIds) > 0 {
		var insertSQL = "insert into role_user(roleid,userid) values"
		var excuteSQL = ""
		var roleid = strconv.Itoa(roleid)

		//执行插入方法
		var insertFunc = func(sql1 string) error {
			sql1 = sql1[0 : len(sql1)-1]
			_, _, err := session.Sqls(sql1).Execute()
			if err != nil {
				session.Rollback()
				srv.log.Errorf("RoleUserService->AuthorizeUser %s", err)
				return err
			}
			return nil
		}

		for i, v := range userIds {
			excuteSQL += "('" + roleid + "','" + v + "'),"
			//100条执行一次
			if i == 99 {
				ierr := insertFunc(insertSQL + excuteSQL)
				if ierr != nil {
					return errors.Wrap(err, "更新角色关联用户失败!")
				}
				excuteSQL = ""
			}
		}

		if len(excuteSQL) > 0 {
			ierr := insertFunc(insertSQL + excuteSQL)
			if ierr != nil {
				return errors.Wrap(err, "更新角色关联用户失败!")
			}
		}

	}

	//casbin 权限控制同步策略
	srv.dao.SQL("delete from casbin_rule where p_type='g' and v1=?", roleid)
	srv.ce.LoadPolicy()
	roleidStr := strconv.Itoa(roleid)
	for _, uid := range userIds {
		srv.ce.AddRoleForUser(uid, roleidStr)
	}

	err = session.Commit()
	if err != nil {
		return errors.Wrap(err, "提交事务失败!")
	}

	return nil
}
